#include "noeudUCT.h"
#include <math.h>
#include "../EPlateau.h"
//#include "arbreUTCtrace.h"


//mpz_class noeudUCT::limite = * new mpz_class(pow(10,50));

// CONSTRUCTEURS
noeudUCT::noeudUCT()
{
        frereG = NULL; // frere gauche, pour trouver tout les fils du pere,
        fils = NULL;

        //ratio
        nbrPassages =0;
        nbrPiecesPosees =0;
        ////nbrFils =0;
        score = 0;

        cout<<"BAD CONSTRUCTOR"<<endl;
        int pause;
        cin>>pause;

}

noeudUCT::noeudUCT(Coup c)
{
        pere = NULL;
        frereG = NULL; // frere gauche, pour trouver tout les fils du pere,
        fils = NULL;

        //ratio
        nbrPassages =0;
        nbrPiecesPosees =0;

        //coup joué sur ce noeud
        coup =c;
        score = 0;
        // bool fini
        cout<<"BAD CONSTRUCTOR COUP C"<<endl;
        int pause;
        cin>>pause;
        //nbrFils =0;
}

noeudUCT::noeudUCT(noeudUCT *p)
{
        pere = p;
        fils = NULL;
        frereG = NULL;

//A SUPPRIMER ! ! !
        //coup.x= 111;
        //coup.y= 111;
//  coup.c = BLANC;  //A CHANGER!
        //ratio
        nbrPassages =0;
        nbrPiecesPosees =0;

        score = 0;
        //nbrFils =0;
        //proba = (* new mpq_class(1,1));
        proba = 1;
        cout<<"BAD CONSTRUCTOR PAS VRAIMENT par copie"<<endl;
        /*int pause;
        cin>>pause;*/
}


noeudUCT::noeudUCT(Coup c, noeudUCT * p, int nbFreres)
{
        // cout<<"creation d'un noeud dans l'arbre"<<endl;
        pere = p;
        frereG = NULL; // frere gauche, pour trouver tout les fils du pere,
        fils = NULL;
        score = 0;
        //recherche de son frere ainé :
        p->addFils( this);

        //ratio
        nbrPassages =0;
        nbrPiecesPosees =0;

        //coup joué sur ce noeud
        coup =c;

        //proba = (* new mpq_class(1,nbFreres));

        proba = (double)1/nbFreres;

        //cout<<"INITIALISATION DE PROBA: "<<proba<<endl;

        //nbrFils =0;

}

noeudUCT::~noeudUCT()
{
        if (fils)
                fils->suppr();
}

void noeudUCT::suppr()
{
        /*if(fils)
            fils->suppr(); */
        if (frereG)
                frereG->suppr() ;
        delete this;
}

/*
void noeudUCT::creerToutLesFils(EPlateau * e) {
    if(fils==NULL){
        //version non recursive!
        //cout<<"creat fils"<<endl;
        int x = 0;
        int y = 0;

        noeudUCT * nTemp =  new noeudUCT();
        fils = nTemp;
        Coup cTemp;
        char c = couleurOppose(coup.c);
        cTemp.c = c;
        while (y<TAILLE){
            if (e->caseJouableUTC(x,y,c)) {
                cTemp.x = x;
                cTemp.y = y;
                //cout<<"creat fils : "<<x<<" - "<<y<<endl;
                nTemp->setFrereG(new noeudUCT(this));
                nTemp = nTemp->getFrereG();
                nTemp->setCoup(cTemp);
                ////nbrFils = fils->creerToutLesFreres(g, x,y, c);
            }

                x++;
            if (x==TAILLE) {
                x = 0;
                y++;
            }
        }
        nTemp->setFrereG(NULL);
        fils = fils->getFrereG();


        //fils->setPere(this);
        int x = 0;
        int y = 0;
        char c = couleurOppose(coup.c);
        while (y<TAILLE && ! g->caseJouableUTC(x,y,c) ) {
            if (x<TAILLE) {
                x++;
            } else {
                x = 0;
                y++;
            }
        }
        if (y<TAILLE) {
            fils = new noeudUCT(this);
            //nbrFils = fils->creerToutLesFreres(g, x,y, c);
        } else {
            fils = NULL;
        }

    }
}

int noeudUCT::creerToutLesFreres(EPlateau * p, int x,int y) {
    coup.x = x ;
    coup.y = y ;
    x++;

    int nbFreres = 0;
    while (y<TAILLE && ! p->caseJouableUTC(x,y,c) ) {
        if (x<TAILLE) {
            x++;
        } else {
            x = 0;
            y++;
        }
    }
    if (y < TAILLE ) {
        frereG = new noeudUCT(pere);
        nbFreres = frereG->creerToutLesFreres(g,x, y, c );
    } else {

        frereG = NULL;
    }
    return 1 + nbFreres;
}

*/
// ACCESSEURS
noeudUCT * noeudUCT::getPere()
{
        return pere ;
}

void noeudUCT::setPere(noeudUCT * p)
{
        pere = p;
}

int noeudUCT::getNbrFils()
{
        int i =0;
        noeudUCT * nTemp = fils;
        while (nTemp !=NULL) {
                //cout<<"cpt fils : "<<i<<" : "<<nTemp->getCoup()<<endl;
                nTemp = nTemp->getFrereG();
                i++;
        }
        return i;
}


noeudUCT * noeudUCT::getFrereG()
{
        return frereG ;
}

void noeudUCT::setFrereG (noeudUCT * n)
{
        frereG = n ;
}

void noeudUCT::setCoup(Coup c)
{
        coup = c;
}

//retourne juste le PREMIER fils
noeudUCT * noeudUCT::getPremierFils()
{
        return fils ;
}

int noeudUCT::getNombreDePassages()
{
        return nbrPassages ;
}
/*
void noeudUCT::setNombreDePassages(int nombreDePassage) {
    nbrPassages = nombreDePassage;
}
*/

int noeudUCT::getNbrPiecesPosees()
{
        return nbrPiecesPosees;
}

/*
void noeudUCT::setNbrPiecesPosees(int nombreDePierresPosees) {
    nbrPiecesPosees = nombreDePierresPosees;
}
*/

bool noeudUCT::getFinni()
{
        return score != 0;
}



Coup noeudUCT::getCoup()
{
        return coup;
}

double noeudUCT::getProba()
{

        return proba;

}


int noeudUCT::getScore()
{
        return score;

}

void noeudUCT::setScore(int cpt)
{
        score = cpt;
}

// METHODE
//retourne le ratio nombre de pieces Posées / nombre de passages
double noeudUCT::getRatio()
{
        return( (double) nbrPiecesPosees / (double)nbrPassages ) ;
}


//retourne TOUS les fils
vector<noeudUCT *> noeudUCT::getTousLesFils()
{
        vector< noeudUCT *> temp; // = new vector<noeudUCT> ; // listes des voisins
        noeudUCT * noeudtemp = fils ;
        while (noeudtemp != NULL) { // on defile les voisins jusqu'a ne plus en avoir
                temp.push_back( noeudtemp);
                noeudtemp = noeudtemp->getFrereG();

        }
        return temp ;
}

//cherche un coup comme fils du noeud et le crée s'il n'existe pas
noeudUCT * noeudUCT::creerFils(Coup c, int nbFreres)
{
        noeudUCT * temp = fils ;
        noeudUCT * lastFrere = fils ;
        while ( temp != NULL && !(temp->getCoup() == c) ) {
                lastFrere = temp;
                temp= temp->getFrereG();
        }
        if (temp !=NULL) {
                // cout<<" fils trouvée et non crée ! ! ! ! "<<endl;
                return temp;
        } else {
                // cout<<" fils crée ! ! ! ! "<<endl;
                noeudUCT * n = new noeudUCT(c, this, nbFreres);//(noeudUCT *) malloc(sizeof(noeudUCT));

                if (lastFrere!=NULL) {
                        lastFrere->setFrereG(n);
                } else {
                        fils = n;
                }
                return n;
        }

}



// ajoute un noeud en tant que fils
void noeudUCT::addFils( noeudUCT * n)
{
        //nbrFils++;
        noeudUCT * temp = fils ;
        if (temp != NULL) // si le noeud courant a deja un fils
        {	// On va l'ajouter en tant que frere de gauche du dernier frere de gauche ;)
                while (temp->getFrereG() != NULL) {
                        //cout<<"j'avance ds la chaine..."<<endl;
                        temp = temp->getFrereG() ;
                }
                temp->setFrereG(n) ;
        } else { // on a pas de fils on rajoute donc en tant que premier
                fils = n;
        }
}


void noeudUCT::passage(int i, double emBranchementTotal)
{

//cout<<"avant le passage: "<<proba<<" embranchement total: "<<emBranchementTotal<<endl;
	   proba *=   ( ((double)1-(emBranchementTotal/proba)) / ((double)1-emBranchementTotal))   ;

	//	cout<<"passage proba: "<<( ((double)1-(emBranchementTotal/proba)) / ((double)1-emBranchementTotal)) <<" - "<<proba<<endl;
//		int pause; cin>>pause;

        nbrPassages++;
        nbrPiecesPosees +=i;


}

/*
void noeudUCT::passage() {
    nbrPassages++;
}

*/
noeudUCT * noeudUCT::getFils()
{
        return fils;
}

noeudUCT * noeudUCT::getFils(Coup c)
{
        //version non recursive.
        noeudUCT * nTemp = fils;
        while (nTemp != NULL && !(c == nTemp->getCoup())) {
                nTemp = nTemp->getFrereG();
        }
        return nTemp;
        /*
        if (fils != NULL)
            return fils->getFrere(c);
        else
            return NULL;
        */
}


noeudUCT * noeudUCT::getFils(Coup c, vector<pthread_mutex_t> * tableMutex, int * cpt)
{
        //version non recursive.
        noeudUCT * nTemp = fils;
        *cpt = 0;
        while (nTemp != NULL && !(c == nTemp->getCoup())) {
                nTemp = nTemp->getFrereG();
                (*cpt)++;
        }
        if (nTemp != NULL && !pthread_mutex_trylock(&(*tableMutex)[*cpt])) {
                return nTemp;
        } else {
                return NULL;
        }
        /*if (fils != NULL)
            return fils->getFrere(c, tableMutex, cpt);
        else
            return NULL;
            */
}

noeudUCT * noeudUCT::getFrere(Coup co,vector<pthread_mutex_t> * tableMutex, int * cpt )
{
        if (co == coup) {
                if (!pthread_mutex_trylock(&(*tableMutex)[*cpt])) {
                        return this;
                } else {
                        return NULL;
                }
        } else if (frereG != NULL) {
                (*cpt)++;
                return frereG->getFrere(co,tableMutex,cpt);
        } else {
                return NULL;
        }
}


noeudUCT * noeudUCT::getFrere(Coup co)
{
        //cout<<" gf : "<<coup.x<<" - "<<coup.y<<endl;
        if (co== coup ) { //Qu : a t'on besoin de verifier la couleur?
                return this;
        } else if (frereG != NULL) {
                return frereG->getFrere(co);
        } else {
                return NULL;
        }
}

double noeudUCT::valeurChoix(/*int n, int etage, int ran*/  int taille, int etage, int pPere)
{
        //return ( getRatio() + sqrt( log( (double) n) / nbrPassages)); // focntion officielle... Toutefois, elle aprait lourde :s... A voir...

        //return ( (( (double) nbrVictoires + 0.5) / (double) (nbrPassages + 1)  )*(etage * etage + 1) + (sqrt( log( (double) n) /( nbrPassages + (etage * etage)  + 1 ))) + (double) 1/(361 * ran)  ); // focntion experimentale... Toutefois, elle aprait lourde :s... A voir...
        // cout<<"valeur choix : "<<nbrPiecesPosees<<" + "<<(taille*taille - 2)<<" / "<<(nbrPassages+1) <<"  = "<<((double)( nbrPiecesPosees +  (taille*taille - 2)) / (double)(getNombreDePassages()+1) )<<endl;
        //cout<<" / "<<(double)(taille * taille)<<" = "<<(((double)( nbrPiecesPosees +  (taille*taille - 2)) / (double)(getNombreDePassages()+1) ) / (double)(taille * taille))<<endl;
        /*
          if(nbrPassages<(taille*taille ) ){
              return 1;
          } else {
        */

        /*cout<<"ratio : "<<( nbrPiecesPosees +  (taille*taille)+1) / (double)(nbrPassages  +1)  / (double)(taille * taille)<<" - "<< (double) nbrPassages / (pPere+1) <<"+ 1 = "<<
            (1 + ((double)( nbrPiecesPosees +  (taille*taille)+1) / (double)(nbrPassages  +1) ) / (double)(taille * taille)  - (double) nbrPassages / (pPere+1)  )<<endl;
            */
        if (score == 0) {
                //    return  (1 + ((double)( nbrPiecesPosees +  (taille*taille)+1) / (double)(nbrPassages  +1) ) / (double)(taille * taille)  - (double) nbrPassages / (pPere+1)  ); //version plus "normal"
                return proba;
        } else {
                return -2;
        }
        //}

        //return (((double)( nbrPiecesPosees +  (taille*taille)+1) / (double)(getNombreDePassages()*getNombreDePassages()+1) ) / (double)(taille * taille)); //version proposant plus de changelents de branches...
}

void noeudUCT::afficher(std::ostream &out)
{
        out << nbrPiecesPosees << "/" << nbrPassages << "m";
}

